﻿using LeRenard.Core.Ui.ConsoleUtils;
using LeRenard.ScriptWars.Model;
using LeRenard.ScriptWars.Model.Entities;
using LeRenard.ScriptWars.Model.GridSystem;
using LeRenard.ScriptWars.Model.Scripting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LeRenard.ScriptWars.UI.Console2D
{
    class Program
    {
        private static void PrintScript(IScript script)
        {
            var defaultColor = Console.ForegroundColor;   

            Console.WriteLine("== SCRIPT ==");
            Console.Write("   Name: ");
            Console.ForegroundColor = ConsoleColor.Black;
            Console.WriteLine("{0}", script.Name);
            Console.ForegroundColor = defaultColor;
            Console.WriteLine("   Algorithm: ");

            foreach (var operation in script.Algorithm.Operations) {
                Console.Write("      {0} {1} [",
                    operation.LineNumber.ToString("00"),
                    operation.Definition.Name);

                foreach (var parameter in operation.Parameters) {
                    Console.Write(" {0}: '{1}'",
                        parameter.Definition.Name,
                        parameter.Value);
                }

                Console.Write(" ];");
                Console.WriteLine();
            }

            Console.WriteLine();
            Console.WriteLine();
        }

        private static void PrintGridTest()
        {
            Console.WriteLine("== GRID ==");
            var random = new Random();
            var initializer = new RandomGridInitializer<string>(() => {
                return random.Next(0, 9).ToString();
            });
            var grid = new Grid<string>(new GridSize(5, 5), initializer);
            Console.WriteLine("   Number of cells: {0} [checksum: {1}]", grid.CellCount, grid.Size.Width * grid.Size.Height);
            Console.WriteLine("   Width: {0}", grid.Size.Width);
            Console.WriteLine("   Height: {0}", grid.Size.Height);
            Console.WriteLine("   Layout:");
            Console.WriteLine();
            for (int y = 0; y < grid.Size.Height; y++) {
                Console.Write("      ");
                for (int x = 0; x < grid.Size.Width; x++) {
                    Console.Write("{0}  ", grid.Layout[y, x].Value);
                }
                Console.WriteLine();
                Console.WriteLine();
            }
            GridPosition p = new GridPosition(1, 2);
            Console.WriteLine("   Position for X={0} and Y={1} => {2}",
                    p.X, p.Y, grid.Layout[p.Y, p.X].Value
                );
            p = new GridPosition(2, 1);
            Console.WriteLine("   Position for X={0} and Y={1} => {2}",
                    p.X, p.Y, grid.Layout[p.Y, p.X].Value
                );
            p = new GridPosition(4, 4);
            Console.WriteLine("   Position for X={0} and Y={1} => {2}",
                    p.X, p.Y, grid.Layout[p.Y, p.X].Value
                );
        }        

        private static void PrintEntityGrid(IGrid<IEntity> grid)
        {
            var defaultColor = Console.ForegroundColor;            

            Console.WriteLine("== GRID ==");
            Console.WriteLine("   Number of cells: {0} [checksum: {1}]", grid.CellCount, grid.Size.Width * grid.Size.Height);
            Console.WriteLine("   Width: {0}", grid.Size.Width);
            Console.WriteLine("   Height: {0}", grid.Size.Height);
            Console.WriteLine("   Layout:");
            Console.WriteLine();
            for (int y = 0; y < grid.Size.Height; y++) {
                Console.Write("      ");
                for (int x = 0; x < grid.Size.Width; x++) {                    
                    var isNull = grid.Layout[y, x].Value == null;
                    var value = isNull ? "*" : grid.Layout[y, x].Value.Script.Name.First().ToString();
                    if (!isNull) {
                        Console.ForegroundColor = ConsoleSession.ClosestConsoleColor(grid.Layout[y, x].Value.Script.Color);
                    }
                    Console.Write("{0}  ", value);
                    Console.ForegroundColor = defaultColor;
                }
                Console.WriteLine();
                Console.WriteLine();
            }
        }

        static void Main(string[] args)
        {
            Console.ReadLine();

            // Prepare scripts
            var scripts = new List<IScript>();
            var wandererScriptFile = new FileInfo("Content/Scripts/Wanderer.txt");
            var wandererScript = Script.FromFile(wandererScriptFile);            
            scripts.Add(wandererScript);
            var linearWalkerScriptFile = new FileInfo("Content/Scripts/LinearWalker.txt");
            var linearWalkerScript = Script.FromFile(linearWalkerScriptFile);            
            scripts.Add(linearWalkerScript);
            var squarerScriptFile = new FileInfo("Content/Scripts/Squarer.txt");
            var squarerScript = Script.FromFile(squarerScriptFile);
            scripts.Add(squarerScript);
          
            // Prepare game
            var game = new Game(scripts, new GridSize(10, 8));

            // Game loop
            ConsoleKeyInfo input;
            bool firstRun = true;
            do {
                // Clear screen
                Console.Clear();

                // Evolve game
                if (!firstRun) {
                    game.Next();
                } else {
                    firstRun = false;
                }

                // Print script
                var scriptsOnGrid = game.Grid.Cells
                    .Where(c => c.Value != null)
                    .Select(c => c.Value.Script)
                    .OrderBy(s => s.Name)
                    .Distinct();
                foreach (var script in scriptsOnGrid) {
                    PrintScript(script);
                }

                // Print Turn
                Console.WriteLine("== TURN #{0} ==", game.Turns.ToString("000"));
                Console.WriteLine();
                Console.WriteLine();

                // Print board
                PrintEntityGrid(game.Grid);

                // One more time?
                /*Console.WriteLine();
                Console.WriteLine("== EXIT ==");
                Console.WriteLine("   Press ENTER to roll next turn");
                Console.WriteLine("   Press R to restart");
                Console.WriteLine("   Press ESC to exit");
                input = Console.ReadKey(true);
                if (input.Key.Equals(ConsoleKey.R))
                    game = new Game(scripts, new GridSize(10, 8));
                 */
                if (scriptsOnGrid.Count() == 1) {
                    Console.WriteLine("== GAME ENDED ==");
                    Console.WriteLine("   Script '{0}' ruled them all.", scriptsOnGrid.Single().Name);
                    break;
                }                

                // Sleep
                Thread.Sleep(20);

            } while (true/*!input.Key.Equals(ConsoleKey.Escape)*/);            

            Console.ReadLine();
        }
    }
}
